#include <cstdlib>
#include <iostream>
#include <memory>
#include <ostream>
#include <string>
#include <sstream>
#include <random>
#include <vector>
#include <chrono>
#include <thread>
#include <regex>

#include "logger_plus_test_lib.h"
#include "gtest/gtest.h"
#include "spdlog/spdlog.h"
#include "BLLDevice.h"

std::shared_ptr<BLLDevice> blldev(nullptr);

TEST(BLLDevice, Base)
{
    fmt::print("\nPlease connect BLL device before test!\nPress Enter to go on.");
    std::cin.get();
    fmt::print("\n\nPlease enter serial port name connect to the device with no space. (example:COM1)\n");
    std::string comname;
    // std::cin >> comname;
    std::getline(std::cin, comname);
    std::transform(comname.begin(), comname.end(), comname.begin(), ::toupper);
    const std::regex base_regex("^COM[0-9]{1,2}$");
    std::smatch base_match;
    if (!std::regex_match(comname, base_match, base_regex)) {
        SPDLOG_WARN("Invalid input, use default serial port!");
        comname = "COM1";
    }

    fmt::print("Use serial port : '{}'\n", comname);
    blldev = std::make_shared<BLLDevice>(comname.c_str(), 0x01); // 0x01, 0x71, 0xF1
    ASSERT_TRUE(blldev);
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    ASSERT_FALSE(blldev->isHasError());
    ASSERT_TRUE(blldev->isInitialized());
    if (blldev->getDevInfo()) {
        fmt::print("found and connected to device : '{}'\n", blldev->getDevInfo());
    }
    ASSERT_NE(blldev->getCH1Status(), -1);
    ASSERT_TRUE((blldev->getCH1Status() & 0x20) == 0);

    blldev->setCurrent(0.99f);
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    ASSERT_FALSE(blldev->isHasError());

    blldev->start();
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    ASSERT_NE(blldev->getCH1Status(), -1);
    fmt::print("channel 1 status is {:08b} after started\n", blldev->getCH1Status());
    ASSERT_TRUE(blldev->isStarted());

    ASSERT_FALSE(blldev->isHasError());
    ASSERT_TRUE(blldev->isTemperatureStabilized());
    ASSERT_NE(blldev->getTemperture(), 0x080);
    ASSERT_NE(blldev->getPower(), 0x01000);
    fmt::print("Device current temperture is {} Celsius degree\n", blldev->getTemperture());
    fmt::print("Device current power is {}mW\n", blldev->getPower());

    blldev->stop();
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    ASSERT_NE(blldev->getCH1Status(), -1);
    fmt::print("channel 1 status is {:08b} after stopped\n", blldev->getCH1Status());
    ASSERT_TRUE(blldev->isStopped());
    ASSERT_FALSE(blldev->isHasError());
}

GTEST_API_ int main(int argc, char** argv)
{
    setLogger(nullptr, 0, 0, nullptr);
    setLoggerLevel(LOG_LEVEL_DEBUG);

    testing::InitGoogleTest(&argc, argv);
    auto ret = RUN_ALL_TESTS();
    blldev.reset(); // return 之后还有线程存在, googletest可能会导致异常
    return ret;
}